package com.yulinlin.lang.util;

import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.List;

public class GenericUtil {

	public static interface DfsWhere{
		boolean where(Class clazz);
	}

	public static Class dfsClass(Type type,DfsWhere dfsWhere){
		Class clazz = null;
		if(type instanceof ParameterizedType){
			Type[] ts = ((ParameterizedType) type).getActualTypeArguments();
			for (Type type1 : ts) {
				clazz = dfsClass(type1,dfsWhere);
				if(clazz != null){
					return clazz;
				}
			}
		}else {

			try{
				clazz =   Class.forName(type.getTypeName());
			}catch (Exception e){
				e.printStackTrace();
			}
			if(dfsWhere.where(clazz)){
				return clazz;
			}else {
				clazz = null;
			}
		}
		if(clazz == null){
			try{
				clazz =   Class.forName(type.getTypeName());
				if(dfsWhere.where(clazz)){
					return clazz;
				}
			}catch (Exception e){
				e.printStackTrace();
			}
		}
		return clazz;
	}




		/**
         * 获得制定类的泛型参数
         * @param from 泛型子类
         * @param to 泛型父类
         * @param index 泛型参数下标
         * @return
         */
	public static Class<?> getGeneric(Class<?> from,Class<?> to,int... index){
		ResolvableType rt=ResolvableType.forClass(from);
		return rt.as(to).getGeneric(index).resolve();  
	}
	

	
	public static Class<?> getFieldGeneric(Field field,int... index){
		ResolvableType resolvableType = ResolvableType.forField(field);
		return resolvableType.getGeneric(index).resolve();
	}

	public static Class searchFieldGeneric(Field field,DfsWhere dfsWhere) {
		LinkedList<Integer> list = new LinkedList();
		searchGeneric(field,dfsWhere,list);
		return getFieldGeneric(field,list);
	}

		static int maxLen = 10;

	/**
	 * 从字段泛型中获取特定类型
	 * @param field
	 * @param
	 * @return
	 */
	private static boolean searchGeneric(Field field,DfsWhere dfsWhere,LinkedList<Integer> list){

		for(int i = 0;i<maxLen;i++){
			list.add(i);
			Class clazz =  getFieldGeneric(field,list);
			if(clazz != null){
				if( dfsWhere.where(clazz)){
					return true;
				}
				boolean b = searchGeneric(field,dfsWhere,list);
				if(b){
					return true;
				}
			}

			list.removeLast();
			if(clazz == null){
				break;
			}
		}

		return false;
	}

  private static LinkedList<Integer> searchGeneric(Field field, Class target) {
	  	LinkedList list =  new LinkedList<>();
		searchGeneric(field,(clazz) ->{
			return target.isAssignableFrom(clazz);
		},list);
		return list;
  }

	public static Class<?> getFieldGeneric(Field method, List<Integer> list) {
		return getFieldGeneric(method, getIndex(list));
	}

  private static int[] getIndex(List<Integer> list){
	  int[] keys = new int[list.size()];
	  for(int i = 0;i<list.size();i++){
		  keys[i]=list.get(i);
	  }
	  return keys;
  }




  //获取方法参数泛型
	public static Class<?> forMethodParameter(Method method, int index,int... keys){
		MethodParameter methodParameter = new MethodParameter(method,index);
		ResolvableType resolvableType = ResolvableType.forMethodParameter(methodParameter);
		return resolvableType.getGeneric(keys).resolve();
	}


	public static Class<?> forMethodReturnType(Method method, int... index){
		ResolvableType resolvableType = ResolvableType.forMethodReturnType(method);

		return resolvableType.getGeneric(index).resolve();
	}



}
